package es.ubu.ceudaaj.exercise.ud02.t04.l03;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

import es.ubu.ceudaaj.exercise.ud02.t04.l03.model.Contactos;
import es.ubu.ceudaaj.exercise.ud02.t04.l03.model.Dataroot;

/**
 * Class representing a list of contacts that can be read and written into and from an xml file.
 * 
 * This version uses JAXB to process the xml.
 * 
 */
public class AgendaJAXB implements Agenda{
    
    private static final String XML_INPUT_PATH = "src/main/resources/xml/Contactos.xml";
    private static final String XML_OUTPUT_PATH = "src/main/resources/xml/Contactos_new.xml";
    
    // Path to the JAXB classes (that have been generated first, by using 'jxc')
    private static final String JAXB_PACKAGE = "es.ubu.ceudaaj.exercise.ud02.t04.l03.model";
    
    // Attribute to keep a reference to the current XML in memory.
    private Dataroot dataroot = null;
    
    private static AgendaJAXB instance= null;
    
    /**
     * Private constructor
     * This class should only be used as singleton
     */
    private AgendaJAXB(){}
    
    /**
     * Returns a JAXB based agenda
     * @return AgendaJAXB
     */
    public static AgendaJAXB getInstance(){
    	if(instance==null) instance = new AgendaJAXB();
    	return instance;
    }
    
    /**
     * Main method responsible for printing the console menu and managing the user selections. 
     * 
     * @param args
     * @throws IOException
     */
//    public static void main( String[] args ) throws IOException {
//        int selectedOption = 0;
//        int selectedContactId = 0;
//        String search = null;
//        System.out.println("hello");
//        
//        // An instance of this class that will represent the current list of contacts.
//        AgendaJAXB agenda = new AgendaJAXB();
//        
//        // Menu loop.
//        while (true) {
//            selectedContactId = 0;
//            
//            Menu.printMenuHeader();
//            
//            agenda.listContacts();
//            
//            Menu.printMainMenu();
//            
//            selectedOption = Menu.readOptionFromConsole();
//            
//            switch (selectedOption) {
//            case 1:
//                agenda.loadXML();
//                Menu.pause();
//                break;
//            case 2:
//                agenda.saveXML();
//                Menu.pause();
//                break;
//            case 3:
//                agenda.createNewContact();
//                break;
//            case 4:
//                selectedContactId = 0;
//                System.out.print("Seleccione el nº de Contacto: ");
//                if ((selectedContactId = Menu.readOptionFromConsole()) > 0) {
//                    agenda.printContactDetail(selectedContactId);
//                } else {
//                	System.out.println("No es un valor valido");
//                }
//                Menu.pause();
//                break;
//            case 5:
//            	selectedContactId = 0;
//                System.out.print("Seleccione el nº de Contacto:");
//                if ((selectedContactId = Menu.readOptionFromConsole()) > 0) {
//                    agenda.editContact(selectedContactId);
//                } else {
//                	System.out.println("No es un valor valido");
//                }
//                Menu.pause();
//                break;
//            case 6:
//                selectedContactId = 0;
//                System.out.print("Seleccione el nº de Contacto: ");
//                if ((selectedContactId = Menu.readOptionFromConsole()) > 0) {
//                    agenda.deleteContact(selectedContactId);
//                } else {
//                	System.out.println("No es un valor valido");
//                }
//                Menu.pause();
//                break;
//            case 7:
//            	System.out.print("Nombre del contacto buscado: ");
//            	search = Menu.readStringFromConsole();
//                if ( search != null && !search.isEmpty()) {
//                    agenda.searchByName(search);
//                } else {
//                	System.out.println("No es un valor valido");
//                }
//                Menu.pause();
//                break;
//            case 8:
//            	System.out.print("Cargo del contacto buscado: ");
//            	search = Menu.readStringFromConsole();
//                if ( search != null && !search.isEmpty()) {
//                    agenda.searchByJob(search);
//                } else {
//                	System.out.println("No es un valor valido");
//                }
//                Menu.pause();
//                break;
//            case 9:
//            	System.out.print("C. Postal del contacto buscado: ");
//            	search = Menu.readStringFromConsole();
//                if ( search != null && !search.isEmpty()) {
//                    agenda.searchByPostalCode(search);
//                } else {
//                	System.out.println("No es un valor valido");
//                }
//                Menu.pause();
//                break;
//            default:
//                System.out.println("No es una opcion valida.");
//                Menu.pause();
//                break;
//            }
//        }
//    }

    /**
     * Shows a list of current contacts on console. (Only name and surnames).
     */
    public void listContacts() {
        int index = 0;
        if (dataroot != null && !dataroot.getContactos().isEmpty()) {
            for (Contactos contact : dataroot.getContactos()) {
                index ++;
                System.out.println(index + ". " 
                        + contact.getApellidos() + ", " + contact.getNombre());
            }
        } else {
            System.out.println("(lista vacia)");
        }
    }
    
    /**
     * Prints detailed information of selected user on console.
     * 
     * @param index Position of selected contact.
     * @throws IOException
     */
    public void printContactDetail(int index) throws IOException {
    	StringBuilder sb;
		if (dataroot != null && dataroot.getContactos() != null
				&& dataroot.getContactos().size() >= index && index > 0) {
			Contactos cont = dataroot.getContactos().get(index - 1);
			sb = new StringBuilder("Detalle del contacto " + index + ": ");
			sb.append("\n\tID: ").append(cont.getIdContacto());
			sb.append("\n\tNombre: ");
			if (cont.getEstimado() != null) {
				sb.append(cont.getEstimado()).append(" ");
			}
			if (cont.getNombre() != null) {
				sb.append(cont.getNombre()).append(" ");
			}
			if (cont.getApellidos() != null) {
				sb.append(cont.getApellidos());
			}
			if (cont.getDireccion() != null) {
				sb.append("\n\tDireccion: ");
				sb.append(cont.getDireccion());
			}
			if (cont.getCodPostal() != null) {
				sb.append(", ").append(cont.getCodPostal());
			}
			if (cont.getCiudad() != null) {
				sb.append(", ").append(cont.getCiudad());
			}
			if (cont.getPais() != null) {
				sb.append(", ").append(cont.getPais());
			}
			if (cont.getCargo() != null) {
				sb.append("\n\tCargo: ").append(cont.getCargo());
			}
			if (cont.getTelefonoTrabajo() != null) {
				sb.append("\n\tTfno. trabajo: ").append(cont.getTelefonoTrabajo());
			}
			if (cont.getExtensionTrabajo() != null) {
				sb.append("\n\tExt. trabajo: ").append(cont.getExtensionTrabajo());
			}
			if (cont.getNumFax() != null) {
				sb.append("\n\tFax: ").append(cont.getNumFax());
			}
			if (cont.getNomCorreoElectronico() != null) {
				sb.append("\n\tEmail: ").append(cont.getNomCorreoElectronico());
			}
			// System.out.println("Tipo contacto: "); //TODO
            //System.out.println("Llamadas: ");//TODO
			System.out.println(sb);
        } else {
            System.out.println("No existe en la lista de contactos.");
        }
    }

    /**
     * Creates a new contact and adds it to the XML representation in memory.
     * 
     * @throws IOException
     */
        public void createNewContact() throws IOException {
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(isr);
        System.out.print("Introduzca Nombre: ");
        String name = br.readLine();
        System.out.print("Introduzca Apellidos: ");
        String surnames = br.readLine();
        System.out.print("Introduzca Telefono: ");
        String phone = br.readLine();
        System.out.print("Introduzca eMail: ");
        String mail = br.readLine();
        
        if (dataroot == null) {
        	dataroot = new Dataroot();
        	GregorianCalendar c = new GregorianCalendar();
        	c.setTime(new Date());
        	XMLGregorianCalendar xmlgc;
			try {
				xmlgc = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
				dataroot.setGenerated(xmlgc);
			} catch (DatatypeConfigurationException e) {
				System.err.println("Error al crear nuevo contacto: " + e);
				return;
			}
        }
        
        Contactos cont = new Contactos();
        cont.setIdContacto(dataroot.getContactos().size() + 1);
        cont.setNombre(name);
        cont.setApellidos(surnames);
        cont.setTelefonoTrabajo(phone);
        cont.setNomCorreoElectronico(mail);
                
        dataroot.getContactos().add(cont);
    }

    /**
     * Method for editing the information for the selected contact in the XML representation in memory.
     * 
     * @param index Position of selected contact.
     * @throws IOException
     */
        public void editContact(int index) throws IOException {
    	if (dataroot != null && dataroot.getContactos() != null 
                && dataroot.getContactos().size() >= index && index > 0) {
    		
    		Contactos contacto = dataroot.getContactos().get(index - 1);
    		String oldName = contacto.getNombre();
    		String oldSurnames = contacto.getApellidos();
    		String oldPhone = contacto.getTelefonoTrabajo();
    		String oldMail = contacto.getNomCorreoElectronico();
    		
    		InputStreamReader isr = new InputStreamReader(System.in);
    		BufferedReader br = new BufferedReader(isr);
    		System.out.print("Introduzca Nombre (o pulse 'Enter' para mantener '"+oldName+"'): ");
    		String name = br.readLine();
    		if (name.isEmpty()) {
    			name = oldName;
    		}
    		System.out.print("Introduzca Apellidos (pulse 'Enter' para mantener '"+oldSurnames+"'): ");
    		String surnames = br.readLine();
    		if (surnames.isEmpty()) {
    			surnames = oldSurnames;
    		}
    		System.out.print("Introduzca Telefono Contacto (pulse 'Enter' para mantener '"+oldPhone+"'): ");
    		String phone = br.readLine();
    		if (phone.isEmpty()) {
    			phone = oldPhone;
    		}
    		System.out.print("Introduzca eMail Contacto (pulse 'Enter' para mantener '"+oldMail+"'): ");
    		String mail = br.readLine();
    		if (mail.isEmpty()) {
    			mail = oldMail;
    		}
    		
    		contacto.setNombre(name);
    		contacto.setApellidos(surnames);
    		contacto.setTelefonoTrabajo(phone);
    		contacto.setNomCorreoElectronico(mail);

    		System.out.println("Se ha editado correctamente el contacto");
    	} else {
            System.out.println("No existe en la lista de contactos.");
        }
    }

    /**
     * Removes the selected contact from the XML representation in memory.
     * 
     * @param index Position of selected contact.
     */
    public void deleteContact(int index) {
        if (dataroot != null && dataroot.getContactos() != null 
                && dataroot.getContactos().size() >= index) {
            dataroot.getContactos().remove(index - 1);
            System.out.println("Contacto borrado.");
        } else {
            System.out.println("No existe en la lista de contactos.");
        }
    }

    /**
     * Writes the current XML in a file.
     */
    public void saveXML() {
    	if (dataroot != null){
	        try {
	            JAXBContext jc = JAXBContext.newInstance(JAXB_PACKAGE);
	            Marshaller marshaller = jc.createMarshaller();
	            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
	            marshaller.marshal(dataroot, new File(XML_OUTPUT_PATH));
	            System.out.println("Se ha guardado correctamente el fichero " + XML_OUTPUT_PATH);
	        } catch (JAXBException ex) {
	            System.err.println("Error al guardar los contactos del XML: " + ex);
	        }
    	} else {
    		System.out.println("Aun no existe ningun contacto");
    	}
    }

    /**
     * Reads the input XML file.
     */
    public void loadXML() {
        try {
            JAXBContext jc = JAXBContext.newInstance(JAXB_PACKAGE);
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            dataroot = (Dataroot)unmarshaller.unmarshal(new File(XML_INPUT_PATH));
            System.out.println("Se ha leido el fichero " + XML_INPUT_PATH);
        } catch (JAXBException ex) {
            System.err.println("Error al obtener los contactos del XML: " + ex);
        }
    }
        

    public void searchByName(String name) {
    	int resultados = 0;
    	List<String> results = new ArrayList<String>();
        for ( Contactos contact : dataroot.getContactos()) {
        	if (contact.getNombre() != null && contact.getNombre().equalsIgnoreCase(name)) {
        		resultados ++;
        		results.add(contact.getNombre() + " " + contact.getApellidos());
        	}
		}
        if (resultados > 0){
	    	System.out.println("Encontrados " + resultados + " resultados: ");
	    	for (int i=0; i<results.size(); i++ ) {
				System.out.println(" Resultado " + (i+1) + ": " + results.get(i)); 
			}
    	} else {
    		System.out.println("No se han encontrado resultados.");
    	}
    }

    public void searchByJob(String job) {
    	int resultados = 0;
    	List<String> results = new ArrayList<String>();
        for ( Contactos contact : dataroot.getContactos()) {
        	if (contact.getCargo() != null && contact.getCargo().equalsIgnoreCase(job)) {
        		resultados ++;
        		results.add(contact.getNombre() + " " + contact.getApellidos());
        	}
		}
        if (resultados > 0){
	    	System.out.println("Encontrados " + resultados + " resultados: ");
	    	for (int i=0; i<results.size(); i++ ) {
				System.out.println(" Resultado " + (i+1) + ": " + results.get(i)); 
			}
    	} else {
    		System.out.println("No se han encontrado resultados.");
    	}
    }

    public void searchByPostalCode(String postalCode) {
    	int resultados = 0;
    	List<String> results = new ArrayList<String>();
        for ( Contactos contact : dataroot.getContactos()) {
        	if (contact.getCodPostal() != null && contact.getCodPostal().equalsIgnoreCase(postalCode)) {
        		resultados ++;
        		results.add(contact.getNombre() + " " + contact.getApellidos());
        	}
		}
        if (resultados > 0){
	    	System.out.println("Encontrados " + resultados + " resultados: ");
	    	for (int i=0; i<results.size(); i++ ) {
				System.out.println(" Resultado " + (i+1) + ": " + results.get(i)); 
			}
    	} else {
    		System.out.println("No se han encontrado resultados.");
    	}
    }
    
}